using Domain.Entities;
using NHibernate;
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Domain.Services
{
    public static class MessageService
    {
        /*****************************************************************************************
        * Getters
        * ***************************************************************************************/
        public static Message GetById(int messageId)
        {
            return NHibernateHelper.GetById<Message>(messageId);
        }

        public static IList<Message> GetLastMessagesByUserId(int userId)
        {
            string query = "from Message msg where msg.Poster.Id = " + userId;
            return NHibernateHelper.ListQuery<Message>(query);
        }

        public static int GetMessageCountForTopic(Topic topic, bool isModerator)
        {
            StringBuilder queryBuilder = new StringBuilder("select count(*) from Message msg where msg.Topic.Id = ");
            queryBuilder.Append(topic.Id);
            if (!isModerator)
            {
                queryBuilder.Append(" and msg.ModeratorsOnly = 0");
            }
            return NHibernateHelper.CountQuery(queryBuilder.ToString());
        }

        public static IList<Message> GetMessagesPaged(
            Topic topic,
            bool isModerator,
            int page,
            int messagesPerPage
        )
        {
            StringBuilder queryBuilder = new StringBuilder("from Message msg where msg.Topic.Id = ");
            queryBuilder.Append(topic.Id);
            if (!isModerator)
            {
                queryBuilder.Append(" and msg.ModeratorsOnly = 0");
            }
            queryBuilder.Append(" order by msg.PostDateTime asc");
            return NHibernateHelper.QueryPaged<Message>(queryBuilder.ToString(), page, messagesPerPage);
        }

        public static int GetOffsetOfMessage(Message message, bool isModerator)
        {
            StringBuilder query = new StringBuilder("select count(*) from Message msg");
            query.Append(" where msg.Topic.Id = ");
            query.Append(message.Topic.Id);
            query.Append(" and msg.PostDateTime <= '");
            query.Append(NHibernateHelper.ConvertDateTime(message.PostDateTime));
            query.Append("'");
            if (!isModerator)
            {
                query.Append(" and msg.ModeratorsOnly = 0");
            }
            return NHibernateHelper.CountQuery(query.ToString());
        }

        public static int GetMessageCountForUser(User user)
        {
            StringBuilder queryBuilder = new StringBuilder();
            queryBuilder.Append("select count(*) from Message msg where msg.Poster.Id = ");
            queryBuilder.Append(user.Id);
            return NHibernateHelper.CountQuery(queryBuilder.ToString());
        }

        public static int GetMessageCountByWeek(DateTime startDate)
        {
            StringBuilder query = new StringBuilder();
            query.Append("select count(*) from Message msg where");
            query.Append(" msg.PostDateTime >='");
            query.Append(NHibernateHelper.ConvertDateTime(startDate));
            query.Append("' and msg.PostDateTime <='");
            query.Append(NHibernateHelper.ConvertDateTime(startDate.AddDays(7)));
            query.Append("'");

            return NHibernateHelper.CountQuery(query.ToString());
        }

        public static IList<Message> GetMessagesPostedByUserPaged(
            User user,
            int page,
            int messagesPerPage
        )
        {
            StringBuilder queryBuilder = new StringBuilder();
            queryBuilder.Append("from Message msg where msg.Poster.Id = ");
            queryBuilder.Append(user.Id);
            queryBuilder.Append(" order by msg.PostDateTime desc");
            return NHibernateHelper.QueryPaged<Message>(queryBuilder.ToString(), page, messagesPerPage);
        }

        public static int GetTotalNumberOfMessages()
        {
            string query = "select count(*) from Message msg";
            return NHibernateHelper.CountQuery(query);
        }

        /*****************************************************************************************
        * Adders
        * ***************************************************************************************/
        public static Message NewMessage(
            Topic topic,
            User poster,
            string text,
            bool moderatorsOnly
        )
        {
            ISession session = NHibernateHelper.Instance.CurrentSession;
            using (ITransaction transaction = session.BeginTransaction())
            {
                Message message = new Message();
                message.Text = text;
                message.PostDateTime = DateTime.Now;
                message.Topic = topic;
                message.Poster = poster;
                message.ModeratorsOnly = moderatorsOnly;
                message.Attachments = new List<Attachment>();
                session.SaveOrUpdate(message);

                topic.NumberOfReplies++;
                topic.LastMessage = message;
                session.SaveOrUpdate(topic);

                Forum forum = topic.Forum;
                forum.NumberOfReplies++;
                session.SaveOrUpdate(forum);

                poster.Posts++;
                session.SaveOrUpdate(poster);

                transaction.Commit();

                return message;
            }
        }

        /*****************************************************************************************
        * Updaters
        * ***************************************************************************************/
        public static void UpdateMessage(Message message, string text, bool moderatorsOnly)
        {
            ISession session = NHibernateHelper.Instance.CurrentSession;
            using (ITransaction transaction = session.BeginTransaction())
            {
                message.Text = text;
                message.ModeratorsOnly = moderatorsOnly;
                session.SaveOrUpdate(message);

                transaction.Commit();
            }
        }

        /*****************************************************************************************
        * Deleters
        * ***************************************************************************************/
        public static void RemoveMessage(Message message)
        {
            ISession session = NHibernateHelper.Instance.CurrentSession;
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(message);

                transaction.Commit();
            }
        }

        public static void AddAttachments(
            Message message,
            IList<Attachment> attachments,
            string filePathFormat
        ) {
            ISession session = NHibernateHelper.Instance.CurrentSession;
            using (ITransaction transaction = session.BeginTransaction())
            {
                foreach (Attachment attachment in attachments)
                {
                    attachment.Settle(message, filePathFormat);
                }

                transaction.Commit();
            }
        }

        public static void EditAttachments(Message message, IList<Attachment> attachments, string filePathFormat)
        {
            ISession session = NHibernateHelper.Instance.CurrentSession;
            using (ITransaction transaction = session.BeginTransaction())
            {
                foreach (Attachment attachment in attachments)
                {
                    if (attachment.Id == 0)
                    {
                        attachment.Settle(message, filePathFormat);
                    }
                }

                List<Attachment> attachmentsToRemove = new List<Attachment>();
                foreach (Attachment attachment in message.Attachments)
                {
                    bool isRemoved = true;
                    foreach (Attachment newAttachment in attachments)
                    {
                        if (newAttachment.Id == attachment.Id)
                        {
                            isRemoved = false;
                            break;
                        }
                    }
                    if (isRemoved)
                    {
                        attachmentsToRemove.Add(attachment);
                    }
                }

                foreach (Attachment attachment in attachmentsToRemove)
                {
                    attachment.Remove();
                }

                transaction.Commit();
            }
        }

        public static Attachment GetAttachment(int attachmentId)
        {
            return NHibernateHelper.GetById<Attachment>(attachmentId);
        }
    }
}
